<?php
namespace cubox;

abstract class App{
    public string $name = '';
    public string $title = '';
    public string $description = '';
    public string $icon = '';
    public string $version = '';
    public string $author = '';
    public string $url = '';
    public string $email = '';
    public string $copyright = '';
    private array $__project = [];

    private array $instances = [];


    public function __call(string $name, array $arguments): mixed{
        throw new \Exception('APP Error:'.$name .' function does not exist');
    }

    public function __init($project){
        $this->__project = $project;
        $this->title = $project['title']??'';
        $this->name = $project['name']??'';
        $this->description = $project['description']??'';
        $this->icon = '/'.APP.'/'. $this->name . '/' . $project['icon']??'';
        $this->version = $project['version']??'';
        $this->author = $project['author']??'';
        $this->url = $project['url']??'';
        $this->email = $project['email']??'';
        $this->copyright = $project['copyright']??'';
    }

    public function init(){
        
    }

    public function config($name):?Data{

        $instance_name = 'config_'.$name;

        if (!isset($this->instances[$instance_name])){
            $this->instances[$instance_name] = new Data(ROOT.DS.CONFIG.DS.$this->name.DS.$name.'.php');
        }
        
        return $this->instances[$instance_name];
    }

    public function cache(string $name='default'):Cache{

        $instance_name = 'cache_'.$name;

        if (!isset($this->instances[$instance_name])){
            $path  = ROOT.DS.CONFIG.DS.$this->name.DS.'cache.php';

            if (file_exists($path)){
                $this->instances[$instance_name] = Cubox::cache($name,$this->config('cache'));
            }else{
                $this->instances[$instance_name] = Cubox::cache($name);
            }
        }

        return $this->instances[$instance_name];
    }

    public function db(string $name='default'){


        $instance_name = 'db_'.$name;

        if (!isset($this->instances[$instance_name])){

            $path  = ROOT.DS.CONFIG.DS.$this->name.DS.'database.php';
        
            if (file_exists($path)){
                $this->instances[$instance_name] = Cubox::db($name,$this->config('database'));
            }else{
                $this->instances[$instance_name] = Cubox::db($name);
            }

        }
        
        return $this->instances[$instance_name];
    }

    public function model(string $name){

        $modelConfig =  [];
        
        if (isset($this->__project['model']) && isset($this->__project['model'][$name])){
            $modelConfig =  $this->__project['model'][$name];
        }else{
            throw new \Exception('Model Error: Model '.$name.' does not exist');
        }

        if (isset($modelConfig['file']) && $modelConfig['file']){
            $className = '\\app\\'.$this->name.'\\model\\'.$name;
            $model = new $className();
        }else{
            $model = new Model();
        }
        
        $model->__init($this,$this->db($modelConfig['config']??'default'),$modelConfig);
        return $model;

    }

    public function url(string $controller,string $action,array $gets=array()){
        return Cubox::url($this->name,$controller,$action,$gets);
    }

    public function run($controller, $action,$gets){
        
        $controllerList =  explode('.', $controller);

        $controllerClassName = '\\app\\'.$this->name.'\\controller';

        foreach ($controllerList as $key => $controllerName){

            if ($key == count($controllerList)-1){
                $controllerName = ucfirst($controllerName);
            }

            $controllerClassName .= '\\'.$controllerName;
        }

        if (class_exists($controllerClassName)){
            
            $actionName =  'on'.ucfirst($action);
            
            $controllerObj = new $controllerClassName();
            $controllerObj->app = $this;
            $controllerObj->name =  $controller;
            $controllerObj->action = $action;
            $controllerObj->gets = $gets;

            if (method_exists($controllerObj, $actionName)){
                return $controllerObj->$actionName();
            } else{
                throw new \Exception($actionName.' not found.');    
            }
        }else{
            throw new \Exception($controllerClassName.' not found.');
        }

    }

    public function checkSetup(){
        return true;
    }
}